// Can I define a generic container, and also define a child class,
// with proper iterators?
// Well, it compiles, but gets confused about iterator inheritance,
// because iterators can't be pure virtual (must be copyable).

#include <list>
#include <iostream>
#include <fstream>

class Collection_Iter {
public:
    typedef Collection_Iter iterator;
    typedef ptrdiff_t difference_type;
    typedef size_t size_type;
    typedef int value_type;
    typedef int * pointer;
    typedef int & reference;

    int x;

public:
    Collection_Iter() {};
    int& operator*() {return x;}
    virtual Collection_Iter operator++() {std::cout << "operator++ in parent\n"; return *this;}
    virtual Collection_Iter operator++(int) {std::cout << "operator++(int) in parent\n"; return *this;}
    virtual bool operator==(const Collection_Iter& other) {std::cout << "operator== in parent\n"; return false;}
    virtual bool operator!=(const Collection_Iter& other) {std::cout << "operator!= in parent\n"; return true;}
};

class Collection_List_Iter : public Collection_Iter {
private:
//    std::list<int> *collection;
    std::list<int>::iterator iter;

public:
//    Collection_List_Iter(std::list<int> *col, int i);
    Collection_List_Iter(std::list<int>::iterator i);
    Collection_List_Iter(const Collection_List_Iter& other);

    int& operator*();
    Collection_Iter operator++();
    Collection_Iter operator++(int);
    bool operator==(const Collection_Iter& other);
    bool operator!=(const Collection_Iter& other);
};

//Collection_List_Iter::Collection_List_Iter(std::list<int> *col, int i) {
Collection_List_Iter::Collection_List_Iter(std::list<int>::iterator i) {
    iter = i;

    std::cout << "Collection_List_Iter::ctor: i points to " << *i
              << ", has addr " << &i << "\n";
    // collection = col;
    // if (i == 0)
    //     iter = collection->begin();
    // else if (i == collection->size())
    //     iter = collection->end();
}

Collection_List_Iter::Collection_List_Iter(const Collection_List_Iter& other) {
//    collection = other.collection;

    std::cout << "Collectino_List_Iter:copy_ctor\n";

    iter = other.iter;
}

int& Collection_List_Iter::operator*() {
    return *iter;
}

Collection_Iter Collection_List_Iter::operator++() {
    iter++;
    return *this;
}

Collection_Iter Collection_List_Iter::operator++(int) {
    Collection_List_Iter clone(*this);
    iter++;
    return clone;
}

bool Collection_List_Iter::operator==(const Collection_Iter& other) {
    std::cout << "operator==\n";

    return iter == ((Collection_List_Iter&)other).iter;
}

bool Collection_List_Iter::operator!=(const Collection_Iter& other) {
    std::cout << "operator!=\n";

    return iter != ((Collection_List_Iter&)other).iter;
//    return !(*this == (Collection_List_Iter&)other);
}

/////////////////////////////////////////////////////////////

class Collection {
public:

    virtual ~Collection() {}

    typedef Collection_Iter iterator;
    typedef ptrdiff_t difference_type;
    typedef size_t size_type;
    typedef int value_type;
    typedef int * pointer;
    typedef int & reference;

    // Iterator handling:
    virtual Collection_Iter begin() = 0;// {return Collection_Iter();}
    virtual Collection_Iter end() = 0;//{return Collection_Iter();}
    virtual void add(int x) {}

    void write(std::ostream& os);

//    friend class Collection_Iter;
};

void Collection::write(std::ostream& os) {
    for (Collection_Iter iter = begin(); iter != end(); ++iter)
        os << ":" << *iter << " ";
    os << "\n";
}

class Collection_List : public Collection {
private:
    std::list<int> items;

    void add(int x);
    Collection_Iter begin();
    Collection_Iter end();
};

void Collection_List::add(int x) {
    items.push_back(x);

    std::cout << "add.  items has " << items.size() << " ints\n";
}

Collection_Iter Collection_List::begin() {

    std::cout << "begin() points to " << *items.begin() << "\n";

    return Collection_List_Iter(items.begin());
}

Collection_Iter Collection_List::end() {

    std::cout << "end()\n";

    return Collection_List_Iter(items.end());
}

int main() {
    Collection *col = new Collection_List();

    col->add(1);
    col->add(2);
    col->add(3);

    col->write(std::cout);
}

